home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / CSG.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  29.1 KB  |  1,409 lines

  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <GL/glut.h>
  5.  
  6. /* Some <math.h> files do not define M_PI... */
  7. #ifndef M_PI
  8. #define M_PI 3.14159265358979323846
  9. #endif
  10.  
  11. #define TRUE    1
  12. #define FALSE    0
  13.  
  14. /*
  15.  * #define the following symbol if you know your glClear honors the
  16.  * stencil mask.  The O2 workstation stencil clear doesn't appear
  17.  * to honor the mask, so we use a workaround.  The workaround may work
  18.  * on any other OpenGL which has this clear bug.
  19.  */
  20. #undef CLEAR_HONORS_STENCIL_MASK
  21.  
  22.  
  23. GLUquadricObj    *quadric;
  24.  
  25.  
  26. int doCSG = 0;
  27. int whereToStop = -1;
  28. typedef enum {CONTINUE, STOP} progressEnum;
  29. int whichTree = 0;
  30. int showSurfaces = 1;
  31. int showOnlyCurrent = 0;
  32. int stenSize;
  33. enum {COLOR, DEPTH, STENCILVALUES, STENCILPLANES} bufferInterest = COLOR;
  34.  
  35.  
  36. void drawFace(void)
  37. {
  38.     glBegin(GL_QUADS);
  39.     glNormal3i(0, 0, 1);
  40.     glVertex3f(1, 1, 1);
  41.     glVertex3f(-1, 1, 1);
  42.     glVertex3f(-1, -1, 1);
  43.     glVertex3f(1, -1, 1);
  44.     glEnd();
  45. }
  46.  
  47.  
  48. void drawBox(void)
  49. {
  50.     glPushMatrix();
  51.  
  52.     drawFace();
  53.  
  54.     glRotatef(90, 1, 0, 0);
  55.     drawFace();
  56.  
  57.     glRotatef(90, 1, 0, 0);
  58.     drawFace();
  59.  
  60.     glRotatef(90, 1, 0, 0);
  61.     drawFace();
  62.  
  63.     glPopMatrix();
  64.  
  65.     glPushMatrix();
  66.  
  67.     glRotatef(90, 0, 1, 0);
  68.     drawFace();
  69.  
  70.     glRotatef(180, 0, 1, 0);
  71.     drawFace();
  72.  
  73.     glPopMatrix();
  74. }
  75.  
  76.  
  77. void drawCylinder(void)
  78. {
  79.     glPushMatrix();
  80.  
  81.     glTranslatef(0, 0, -.5);
  82.     gluCylinder(quadric, 1, 1, 1, 30, 5);
  83.  
  84.     glRotatef(180, 0, 1, 0);
  85.     gluDisk(quadric, 0, 1, 30, 2);
  86.  
  87.     glPopMatrix();
  88.  
  89.     glPushMatrix();
  90.  
  91.     glTranslatef(0, 0, .5);
  92.     gluDisk(quadric, 0, 1, 30, 2);
  93.  
  94.     glPopMatrix();
  95. }
  96.  
  97.  
  98. void drawCone(void)
  99. {
  100.     glPushMatrix();
  101.  
  102.     glTranslatef(0, 0, -.5);
  103.     gluCylinder(quadric, 1, 0, 1, 30, 5);
  104.  
  105.     glRotatef(180, 0, 1, 0);
  106.     gluDisk(quadric, 0, 1, 30, 2);
  107.  
  108.     glPopMatrix();
  109. }
  110.  
  111.  
  112. void drawSphere(void)
  113. {
  114.     gluSphere(quadric, 1, 30, 20);
  115. }
  116.  
  117.  
  118. struct transformation {
  119.     float    translation[3];
  120.     float    rotation[4];
  121.     float    scale[3];
  122. };
  123.  
  124.  
  125. struct primitive {
  126.     float        color[4];
  127.     void        (*draw)(void);
  128.     struct transformation    xform;
  129. };
  130.  
  131.  
  132. struct transformation globalXform = {
  133.     0, 0, 0,
  134.     1, 0, 0, 0,
  135.     1, 1, 1
  136. };
  137.  
  138.  
  139. struct primitive prims[20] = {
  140.     {
  141.         {.5, .5, 1},
  142.     drawBox,
  143.     {
  144.         -3, 0, 0,
  145.         1, 0, 0, 0,
  146.         1, 1, 1
  147.     }
  148.     },
  149.     {
  150.         {1, .5, .5},
  151.     drawCylinder,
  152.     {
  153.         -1, 0, 0,
  154.         1, 0, 0, 0,
  155.         1, 1, 1
  156.     }
  157.     },
  158.     {
  159.         {.5, 1, .5},
  160.     drawCone,
  161.     {
  162.         1, 0, 0,
  163.         1, 0, 0, 0,
  164.         1, 1, 1
  165.     }
  166.     },
  167.     {
  168.         {1, .5, 1},
  169.     drawSphere,
  170.     {
  171.         3, 0, 0,
  172.         1, 0, 0, 0,
  173.         1, 1, 1
  174.     }
  175.     }
  176. };
  177.  
  178.  
  179. int numPrims = 4;
  180. int curPrim = 0;
  181.  
  182.  
  183. void drawXform(struct transformation *xform, int applyScale)
  184. {
  185.     glTranslatef(xform->translation[0], xform->translation[1], xform->translation[2]);
  186.     glRotatef(xform->rotation[3] / M_PI * 180, xform->rotation[0], xform->rotation[1], xform->rotation[2]);
  187.     if(applyScale)
  188.     glScalef(xform->scale[0], xform->scale[1], xform->scale[2]);
  189. }
  190.  
  191.  
  192. int magicTranspHack = 0;
  193.  
  194.  
  195. void drawPrim(int i)
  196. {
  197.     struct primitive *p = &prims[i];
  198.     struct transformation *xform = &p->xform;
  199.  
  200.     if(magicTranspHack)
  201.     {
  202.         float c[4];
  203.     c[0] = p->color[0];
  204.     c[1] = p->color[1];
  205.     c[2] = p->color[2];
  206.     c[3] = .25;
  207.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, c);
  208.     }
  209.     else
  210.     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, p->color);
  211.     glPushMatrix();
  212.     drawXform(xform, TRUE);
  213.     p->draw();
  214.     glPopMatrix();
  215. }
  216.  
  217.  
  218. struct product {
  219.     int targetPrim;
  220.     int frontFace;
  221.     int whichSurface;
  222.     int numTrimPrims;
  223.     int *trimmingPrims;
  224.     int *isComplemented;
  225. };
  226.  
  227.  
  228. int prodAtrimmingPrims1[] = {1};
  229. int prodAisComplemented1[] = {1};
  230. int prodBtrimmingPrims1[] = {0};
  231. int prodBisComplemented1[] = {0};
  232.  
  233.  
  234. int prodAtrimmingPrims2[] = {1};
  235. int prodAisComplemented2[] = {0};
  236. int prodBtrimmingPrims2[] = {0};
  237. int prodBisComplemented2[] = {1};
  238.  
  239.  
  240. int prodAtrimmingPrims3[] = {1};
  241. int prodAisComplemented3[] = {0};
  242. int prodBtrimmingPrims3[] = {0};
  243. int prodBisComplemented3[] = {0};
  244.  
  245.  
  246. int prodAtrimmingPrims4[] = {1, 2, 3};
  247. int prodAisComplemented4[] = {0, 1, 1};
  248. int prodBtrimmingPrims4[] = {1, 0, 2};
  249. int prodBisComplemented4[] = {0, 0, 1};
  250. int prodCtrimmingPrims4[] = {1, 0, 3};
  251. int prodCisComplemented4[] = {0, 0, 1};
  252. int prodDtrimmingPrims4[] = {0, 2, 3};
  253. int prodDisComplemented4[] = {0, 1, 1};
  254.  
  255.  
  256. struct product products[][4] = {
  257.     {    /* A - B */
  258.     {
  259.         0, 1, 0,
  260.         1,
  261.         prodAtrimmingPrims1,
  262.         prodAisComplemented1,
  263.     },
  264.     {
  265.         1, 0, 0,
  266.         1,
  267.         prodBtrimmingPrims1,
  268.         prodBisComplemented1,
  269.     },
  270.     },
  271.  
  272.     {    /* B - A */
  273.     {
  274.         0, 0, 0,
  275.         1,
  276.         prodAtrimmingPrims2,
  277.         prodAisComplemented2,
  278.     },
  279.     {
  280.         1, 1, 0,
  281.         1,
  282.         prodBtrimmingPrims2,
  283.         prodBisComplemented2,
  284.     },
  285.     },
  286.  
  287.     {    /* A and B */
  288.     {
  289.         0, 1, 0,
  290.         1,
  291.         prodAtrimmingPrims3,
  292.         prodAisComplemented3,
  293.     },
  294.     {
  295.         1, 1, 0,
  296.         1,
  297.         prodBtrimmingPrims3,
  298.         prodBisComplemented3,
  299.     },
  300.     },
  301.  
  302.     { /* A and B - D - C */
  303.     {
  304.         0, 1, 0,
  305.         3,
  306.         prodAtrimmingPrims4,
  307.         prodAisComplemented4,
  308.     },
  309.     {
  310.         3, 0, 0,
  311.         3,
  312.         prodBtrimmingPrims4,
  313.         prodBisComplemented4,
  314.     },
  315.     {
  316.         2, 0, 0,
  317.         3,
  318.         prodCtrimmingPrims4,
  319.         prodCisComplemented4,
  320.     },
  321.     {
  322.         1, 1, 0,
  323.         3,
  324.         prodDtrimmingPrims4,
  325.         prodDisComplemented4,
  326.     },
  327.     },
  328. };
  329.  
  330.  
  331. int numProducts[4] = {2, 2, 2, 4};
  332.  
  333.  
  334. int         winWidth, winHeight;
  335. GLfloat     *depthSave = NULL;
  336. GLubyte     *stencilSave = NULL;
  337. GLubyte     *colorSave = NULL;
  338.  
  339.  
  340. void resizeBuffers(void)
  341. {
  342.     if(colorSave != NULL)
  343.         free(colorSave);
  344.     colorSave = malloc(winWidth * winHeight * 4 * sizeof(GLubyte));
  345.     if(depthSave != NULL)
  346.         free(depthSave);
  347.     depthSave = malloc(winWidth * winHeight * sizeof(GLfloat));
  348.     stencilSave = (GLubyte *)depthSave;
  349. }
  350.  
  351.  
  352. void pushOrthoView(float left, float right, float bottom, float top,
  353.     float znear, float zfar)
  354. {
  355.     glPushMatrix();
  356.     glLoadIdentity();
  357.     glMatrixMode(GL_PROJECTION);
  358.     glPushMatrix();
  359.     glLoadIdentity();
  360.     glOrtho(left, right, bottom, top, znear, zfar);
  361. }
  362.  
  363.  
  364. void popView(void)
  365. {
  366.     glPopMatrix();
  367.     glMatrixMode(GL_MODELVIEW);
  368.     glPopMatrix();
  369. }
  370.  
  371.  
  372. void copyDepthToColor(GLenum whichColorBuffer)
  373. {
  374.     int        x, y;
  375.     GLfloat    max, min;
  376.     GLint    previousColorBuffer;
  377.  
  378.     glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT, GL_FLOAT,
  379.         depthSave);
  380.  
  381.     /* I'm sure this could be done much better with OpenGL */
  382.     max = 0;
  383.     min = 1;
  384.     for(y = 0; y < winHeight; y++)
  385.     for(x = 0; x < winWidth; x++) {
  386.         if(depthSave[winWidth * y + x] < min)
  387.         min = depthSave[winWidth * y + x];
  388.         if(depthSave[winWidth * y + x] > max && depthSave[winWidth * y + x] < .999)
  389.         max = depthSave[winWidth * y + x];
  390.     }
  391.  
  392.     for(y = 0; y < winHeight; y++)
  393.     for(x = 0; x < winWidth; x++) {
  394.         if(depthSave[winWidth * y + x] <= max)
  395.         depthSave[winWidth * y + x] = 1 -  (depthSave[winWidth * y + x] - min) / (max - min);
  396.         else
  397.         depthSave[winWidth * y + x] = 0;
  398.     }
  399.  
  400.     pushOrthoView(0, 1, 0, 1, 0, 1);
  401.     glRasterPos3f(0, 0, -.5);
  402.     glDisable(GL_DEPTH_TEST);
  403.     glDisable(GL_STENCIL_TEST);
  404.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  405.     glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
  406.     glDrawBuffer(whichColorBuffer);
  407.     glDrawPixels(winWidth, winHeight, GL_LUMINANCE , GL_FLOAT, depthSave);
  408.     glDrawBuffer(previousColorBuffer);
  409.     glEnable(GL_DEPTH_TEST);
  410.     popView();
  411. }
  412.  
  413.  
  414. unsigned char stencilValueToColorMap[][3] =
  415. {
  416.     {255, 0, 0},    /* red */
  417.     {255, 218, 0},    /* yellow */
  418.     {72, 255, 0},    /* yellowish green */
  419.     {0, 255, 145},    /* bluish cyan */
  420.     {0, 145, 255},    /* cyanish blue */
  421.     {72, 0, 255},    /* purplish blue */
  422.     {255, 0, 218},    /* reddish purple */
  423. };
  424.  
  425.  
  426. void copyStencilValuesToColor(GLenum whichColorBuffer)
  427. {
  428.     int        x, y;
  429.     GLint    previousColorBuffer;
  430.  
  431.     glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
  432.         stencilSave);
  433.  
  434.     /* I'm sure this could be done much better with OpenGL */
  435.     for(y = 0; y < winHeight; y++)
  436.     for(x = 0; x < winWidth; x++) {
  437.         int stencilValue;
  438.         
  439.         stencilValue = stencilSave[winWidth * y + x];
  440.  
  441.         colorSave[(winWidth * y + x) * 3 + 0] =
  442.             stencilValueToColorMap[stencilValue % 7][0];
  443.         colorSave[(winWidth * y + x) * 3 + 1] =
  444.             stencilValueToColorMap[stencilValue % 7][1];
  445.         colorSave[(winWidth * y + x) * 3 + 2] =
  446.             stencilValueToColorMap[stencilValue % 7][2];
  447.     }
  448.  
  449.     pushOrthoView(0, 1, 0, 1, 0, 1);
  450.     glRasterPos3f(0, 0, -.5);
  451.     glDisable(GL_DEPTH_TEST);
  452.     glDisable(GL_STENCIL_TEST);
  453.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  454.     glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
  455.     glDrawBuffer(whichColorBuffer);
  456.     glDrawPixels(winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, colorSave);
  457.     glDrawBuffer(previousColorBuffer);
  458.     glEnable(GL_DEPTH_TEST);
  459.     popView();
  460. }
  461.  
  462.  
  463. /*
  464.  * XXX This function should make colors that identify individual bits in
  465.  * the stencil buffer, but it seems like too hard a problem to solve
  466.  * in five minutes.  Fix later.
  467.  */
  468. void copyStencilPlanesToColor(GLenum whichColorBuffer)
  469. {
  470.     int        x, y;
  471.     GLint    previousColorBuffer;
  472.  
  473.     glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
  474.         stencilSave);
  475.  
  476.     /* I'm sure this could be done much better with OpenGL */
  477.     for(y = 0; y < winHeight; y++)
  478.     for(x = 0; x < winWidth; x++) {
  479.         /* Have to think of something clever to do here */
  480.     }
  481.  
  482.     pushOrthoView(0, 1, 0, 1, 0, 1);
  483.     glRasterPos3f(0, 0, -.5);
  484.     glDisable(GL_DEPTH_TEST);
  485.     glDisable(GL_STENCIL_TEST);
  486.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  487.     glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
  488.     glDrawBuffer(whichColorBuffer);
  489.     glDrawPixels(winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, colorSave);
  490.     glDrawBuffer(previousColorBuffer);
  491.     glEnable(GL_DEPTH_TEST);
  492.     popView();
  493. }
  494.  
  495.  
  496. void copyInterest(void)
  497. {
  498.     switch(bufferInterest) {
  499.         case COLOR:
  500.         break; /* Well, that's already there. */
  501.  
  502.     case STENCILVALUES:
  503.         copyStencilValuesToColor(GL_BACK);
  504.         break;
  505.  
  506.     case STENCILPLANES:
  507.         copyStencilPlanesToColor(GL_BACK);
  508.         break;
  509.  
  510.     case DEPTH:
  511.         copyDepthToColor(GL_BACK);
  512.         break;
  513.     }
  514. }
  515.  
  516.  
  517. void axisamountToMat(float aa[], float mat[])
  518. {
  519.     float c, s, t;
  520.  
  521.     c = (float)cos(aa[3]);
  522.     s = (float)sin(aa[3]);
  523.     t = 1.0f - c;
  524.  
  525.     mat[0] = t * aa[0] * aa[0] + c;
  526.     mat[1] = t * aa[0] * aa[1] + s * aa[2];
  527.     mat[2] = t * aa[0] * aa[2] - s * aa[1];
  528.     mat[3] = t * aa[0] * aa[1] - s * aa[2];
  529.     mat[4] = t * aa[1] * aa[1] + c;
  530.     mat[5] = t * aa[1] * aa[2] + s * aa[0];
  531.     mat[6] = t * aa[0] * aa[2] + s * aa[1];
  532.     mat[7] = t * aa[1] * aa[2] - s * aa[0];
  533.     mat[8] = t * aa[2] * aa[2] + c;
  534. }
  535.  
  536.  
  537. void matToAxisamount(float mat[], float aa[])
  538. {
  539.     float c;
  540.     float s;
  541.  
  542.     c = (mat[0] + mat[4] + mat[8] - 1.0f) / 2.0f;
  543.     aa[3] = (float)acos(c);
  544.     s = (float)sin(aa[3]);
  545.     if(fabs(s / M_PI - (int)(s / M_PI)) < .0000001)
  546.     {
  547.         aa[0] = 0.0f;
  548.         aa[1] = 1.0f;
  549.         aa[2] = 0.0f;
  550.     }
  551.     else
  552.     {
  553.     aa[0] = (mat[5] - mat[7]) / (2.0f * s);
  554.     aa[1] = (mat[6] - mat[2]) / (2.0f * s);
  555.     aa[2] = (mat[1] - mat[3]) / (2.0f * s);
  556.     }
  557. }
  558.  
  559.  
  560. void multMat(float m1[], float m2[], float r[])
  561. {
  562.     float t[9];
  563.     int i;
  564.  
  565.     t[0] = m1[0] * m2[0] + m1[1] * m2[3] + m1[2] * m2[6];
  566.     t[1] = m1[0] * m2[1] + m1[1] * m2[4] + m1[2] * m2[7];
  567.     t[2] = m1[0] * m2[2] + m1[1] * m2[5] + m1[2] * m2[8];
  568.     t[3] = m1[3] * m2[0] + m1[4] * m2[3] + m1[5] * m2[6];
  569.     t[4] = m1[3] * m2[1] + m1[4] * m2[4] + m1[5] * m2[7];
  570.     t[5] = m1[3] * m2[2] + m1[4] * m2[5] + m1[5] * m2[8];
  571.     t[6] = m1[6] * m2[0] + m1[7] * m2[3] + m1[8] * m2[6];
  572.     t[7] = m1[6] * m2[1] + m1[7] * m2[4] + m1[8] * m2[7];
  573.     t[8] = m1[6] * m2[2] + m1[7] * m2[5] + m1[8] * m2[8];
  574.     for(i = 0; i < 9; i++)
  575.     {
  576.         r[i] = t[i];
  577.     }
  578. }
  579.  
  580.  
  581. void rotateTrackball(int dx, int dy, float rotation[4])
  582. {
  583.     float dist;
  584.     float oldMat[9];
  585.     float rotMat[9];
  586.     float newRot[4];
  587.  
  588.     dist = (float)sqrt((double)(dx * dx + dy * dy));
  589.     if(fabs(dist) < 0.99)
  590.         return;
  591.  
  592.     newRot[0] = (float) dy / dist;
  593.     newRot[1] = (float) dx / dist;
  594.     newRot[2] = 0.0f;
  595.     newRot[3] = (float)M_PI * dist / winWidth;
  596.  
  597.     axisamountToMat(rotation, oldMat);
  598.     axisamountToMat(newRot, rotMat);
  599.     multMat(oldMat, rotMat, oldMat);
  600.     matToAxisamount(oldMat, rotation);
  601.  
  602.     dist = (float)sqrt(rotation[0] * rotation[0] + rotation[1] * rotation[1] +
  603.         rotation[2] * rotation[2]);
  604.  
  605.     rotation[0] /= dist;
  606.     rotation[1] /= dist;
  607.     rotation[2] /= dist;
  608. }
  609.  
  610.  
  611. struct transformation *curXform;
  612.  
  613.  
  614. void init(void)
  615. {
  616.     glMatrixMode(GL_PROJECTION);
  617.     glFrustum(-.33, .33, -.33, .33, .5, 40);
  618.  
  619.     glMatrixMode(GL_MODELVIEW);
  620.     gluLookAt(0, 0, 7, 0, 0, 0, 0, 1, 0);
  621.  
  622.     glEnable(GL_LIGHTING);
  623.     glEnable(GL_LIGHT0);
  624.  
  625.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  626.  
  627.     glEnable(GL_NORMALIZE);
  628.  
  629.     quadric = gluNewQuadric();
  630.  
  631.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  632.  
  633.     curXform = &prims[0].xform;
  634. }
  635.  
  636.  
  637. void setupLight(void)
  638. {
  639.     static GLfloat lightpos[] = {0, 1, 0, 0};
  640.  
  641.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  642. }
  643.  
  644.  
  645. void redrawNoCSG(void)
  646. {
  647.     int i;
  648.  
  649.     glDisable(GL_STENCIL_TEST);
  650.     glEnable(GL_DEPTH_TEST);
  651.     glDepthFunc(GL_LESS);
  652.     glEnable(GL_CULL_FACE);
  653.     glCullFace(GL_BACK);
  654.     glDepthMask(GL_TRUE);
  655.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  656.  
  657.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  658.  
  659.     glPushMatrix();
  660.  
  661.     drawXform(&globalXform, FALSE);
  662.  
  663.     for(i = 0; i < numPrims; i++)
  664.     {
  665.         if(i == curPrim || !showOnlyCurrent)
  666.         drawPrim(i);
  667.     }
  668.  
  669.     glPopMatrix();
  670.  
  671.     copyInterest();
  672.  
  673.     glutSwapBuffers();
  674. }
  675.  
  676.  
  677. int whereSoFar;
  678.  
  679.  
  680. GLfloat *depthResults = NULL;
  681.  
  682.  
  683. void saveDepth(void)
  684. {
  685.     depthResults = realloc(depthResults, winWidth * winHeight *
  686.         sizeof(GLfloat));
  687.     glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT, GL_FLOAT,
  688.     depthResults);
  689. }
  690.  
  691.  
  692. void restoreDepth(void)
  693. {
  694.     glStencilMask(0);
  695.     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  696.     glDepthMask(GL_TRUE);
  697.     glEnable(GL_DEPTH_TEST);
  698.     glDepthFunc(GL_ALWAYS);
  699.     glDisable(GL_STENCIL_TEST);
  700.  
  701.     pushOrthoView(0, 1, 0, 1, 0, 1);
  702.     glRasterPos3f(0, 0, -.5);
  703.  
  704.     glDrawPixels(winWidth, winHeight, GL_DEPTH_COMPONENT, GL_FLOAT,
  705.         depthResults);
  706.  
  707.     popView();
  708. }
  709.  
  710.  
  711. #define COPY_AND_RETURN_IF_DONE(s) \
  712.     { \
  713.     if(whereSoFar++ == whereToStop) { \
  714.         printf("%s\n", s); \
  715.         return(STOP);  \
  716.     } \
  717.     }
  718.  
  719.  
  720. #define COPY_AND_GOTO_IF_DONE(s) \
  721.     { \
  722.     if(whereSoFar++ == whereToStop) { \
  723.         printf("%s\n", s); \
  724.         goto doneWithFrame;  \
  725.     } \
  726.     }
  727.  
  728.  
  729. int sCountMask = 0x01;    /* 1-convexity maximum */
  730. int sCountShift = 0;
  731. int sPMask = 1;
  732. int sPShift = 0;
  733.  
  734.  
  735. void drawFarRect(void)
  736. {
  737.     pushOrthoView(0, 1, 0, 1, 0, 1);
  738.  
  739.     /* Can I just draw & let be clipped? */
  740.     glBegin(GL_QUADS);
  741.     glVertex3f(0, 0, -1);
  742.     glVertex3f(1, 0, -1);
  743.     glVertex3f(1, 1, -1);
  744.     glVertex3f(0, 1, -1);
  745.     glEnd();
  746.  
  747.     popView();
  748. }
  749.  
  750.  
  751. progressEnum renderPrimDepths(int targetPrim, int frontFace, int whichSurface)
  752. {
  753.     glClear(GL_DEPTH_BUFFER_BIT);
  754.  
  755.  
  756.     glDepthFunc(GL_ALWAYS);
  757.     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  758.     glStencilMask(sCountMask);
  759.  
  760. #ifndef CLEAR_HONORS_STENCIL_MASK /* see comment at beginning of source */
  761.  
  762.     glDisable(GL_CULL_FACE);
  763.     glDisable(GL_DEPTH_TEST);
  764.     glDepthMask(GL_FALSE);
  765.  
  766.     glStencilFunc(GL_ALWAYS, 0, 0);
  767.     glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  768.     drawFarRect();
  769.  
  770.     COPY_AND_RETURN_IF_DONE("After clearing p bit in stencil");
  771.  
  772. #else
  773.  
  774.     glClearStencil(0);
  775.     glClear(GL_STENCIL_BUFFER_BIT);
  776.  
  777. #endif
  778.  
  779.     glEnable(GL_CULL_FACE);
  780.     if(frontFace)
  781.         glCullFace(GL_BACK);
  782.     else
  783.         glCullFace(GL_FRONT);
  784.  
  785.     glEnable(GL_DEPTH_TEST);
  786.     glDepthMask(GL_TRUE);
  787.  
  788.     glStencilFunc(GL_EQUAL, whichSurface, sCountMask);
  789.     glStencilOp(GL_INCR, GL_INCR, GL_INCR);
  790.  
  791.     drawPrim(targetPrim);
  792.  
  793.     return(CONTINUE);
  794. }
  795.  
  796.  
  797. progressEnum trimWithPrimitive(int trimPrim, int isComplemented)
  798. {
  799.     glDepthFunc(GL_LESS);
  800.     glEnable(GL_STENCIL_TEST);
  801.     glDepthMask(GL_FALSE);
  802.     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  803.     glStencilMask(sPMask);
  804.     glDisable(GL_CULL_FACE);
  805.  
  806. #ifndef CLEAR_HONORS_STENCIL_MASK /* see comment at beginning of source */
  807.  
  808.     glDisable(GL_DEPTH_TEST);
  809.  
  810.     glStencilFunc(GL_ALWAYS, isComplemented ? (1 << sPShift) : 0, 0);
  811.     glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  812.     drawFarRect();
  813.  
  814. #else
  815.  
  816.     glClearStencil(isComplemented ? (1 << sPShift) : 0);
  817.     glClear(GL_STENCIL_BUFFER_BIT);
  818.  
  819. #endif
  820.  
  821.     glEnable(GL_DEPTH_TEST);
  822.     glStencilFunc(GL_ALWAYS, 0, 0);
  823.     glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT);
  824.     drawPrim(trimPrim);
  825.  
  826.     COPY_AND_RETURN_IF_DONE("After setting stencil to mark depths "
  827.         "inside trimming primitive");
  828.  
  829.     /* stencil == 0 where pixels were not inside */
  830.     /* so now set Z to far where stencil == 0, everywhere pixels trimmed */
  831.  
  832.     glStencilFunc(GL_EQUAL, 0, sPMask);
  833.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  834.     glDepthMask(1);
  835.     glDepthFunc(GL_ALWAYS);
  836.     glDisable(GL_LIGHTING);
  837.     drawFarRect();
  838.     glEnable(GL_LIGHTING);
  839.  
  840.     COPY_AND_RETURN_IF_DONE("After clearing depths where target outside "
  841.         "trimming primitive");
  842.  
  843.     return(CONTINUE);
  844. }
  845.  
  846.  
  847. progressEnum markProductPixels(int product, int accumBit)
  848. {
  849.     int i;
  850.  
  851.     struct product *p;
  852.  
  853.     p = &products[whichTree][product];
  854.  
  855.     if(renderPrimDepths(p->targetPrim, p->frontFace, p->whichSurface) == STOP)
  856.         return(STOP);
  857.  
  858.     COPY_AND_RETURN_IF_DONE("After rendering target depths");
  859.  
  860.     for(i = 0; i < p->numTrimPrims; i++)
  861.     {
  862.         if(trimWithPrimitive(p->trimmingPrims[i], p->isComplemented[i]) == STOP)
  863.         return(STOP);
  864.     }
  865.  
  866.     COPY_AND_RETURN_IF_DONE("After target has been trimmed by all "
  867.         "trimming primitives");
  868.  
  869.     /* set accumulator stencil bit for this primitive everywhere depth != far */
  870.     glStencilFunc(GL_ALWAYS, 1 << accumBit, 0);
  871.     glStencilOp(GL_KEEP, GL_ZERO, GL_REPLACE);
  872.     glStencilMask(1 << accumBit);
  873.     glDepthMask(0);
  874.     glDepthFunc(GL_GREATER);
  875.     glDisable(GL_LIGHTING);
  876.     drawFarRect();
  877.     glEnable(GL_LIGHTING);
  878.  
  879.     COPY_AND_RETURN_IF_DONE("After setting accumulator where depths != far");
  880.  
  881.     return(CONTINUE);
  882. }
  883.  
  884.  
  885. progressEnum drawProduct(int product, int accumBit)
  886. {
  887.     struct product *p;
  888.     p = &products[whichTree][product];
  889.  
  890.     glEnable(GL_CULL_FACE);
  891.     if(p->frontFace)
  892.         glCullFace(GL_BACK);
  893.     else
  894.         glCullFace(GL_FRONT);
  895.  
  896.     glDepthMask(GL_TRUE);
  897.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  898.     glEnable(GL_DEPTH_TEST);
  899.     glDepthFunc(GL_LESS);
  900.     glEnable(GL_STENCIL_TEST);
  901.     glStencilFunc(GL_EQUAL, 1 << accumBit, 1 << accumBit);
  902.     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  903.     drawPrim(p->targetPrim);
  904.  
  905.     COPY_AND_RETURN_IF_DONE("After drawing target color and depth");
  906.  
  907.     return(CONTINUE);
  908. }
  909.  
  910.  
  911. void redrawCSG(void)
  912. {
  913.     int i;
  914.     int accumBit;
  915.     int firstProduct;
  916.     int lastProduct;
  917.  
  918.     whereSoFar = 0;
  919.     glDepthMask(GL_TRUE);
  920.     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); 
  921.     glClear(GL_COLOR_BUFFER_BIT);
  922.  
  923.     /* Only have to do this if you're going to look at the stencil buffer */
  924.     glClearStencil(0);
  925.     glStencilMask((1 << stenSize) - 1);
  926.     glClear(GL_STENCIL_BUFFER_BIT);
  927.  
  928.     glPushMatrix();
  929.  
  930.     drawXform(&globalXform, FALSE);
  931.  
  932.     firstProduct = 0;
  933.  
  934.     while(firstProduct != numProducts[whichTree]) {
  935.     
  936.      /*
  937.      * set lastProduct so that accum bits for first to last fit in
  938.      * stencil buffer minus bits needed for surface counting bits
  939.      */
  940.     lastProduct = firstProduct + (stenSize - 1) - 1;
  941.     if(lastProduct >= numProducts[whichTree])
  942.         lastProduct = numProducts[whichTree] - 1;
  943.  
  944.     if(firstProduct > 0)    /* know depth is clear before 1st group */
  945.         saveDepth();    
  946.  
  947.     accumBit = 1;        /* first available after counting bits */
  948.  
  949.     for(i = firstProduct; i <= lastProduct; i++)
  950.         if(markProductPixels(i, accumBit++) == STOP)
  951.         goto doneWithFrame;
  952.  
  953.     COPY_AND_GOTO_IF_DONE("After marking \"inside\" target accumulators");
  954.  
  955.     if(firstProduct > 0)    /* know depth was clear before first group */
  956.         restoreDepth();
  957.     else {
  958.         glDepthMask(GL_TRUE);
  959.         glClear(GL_DEPTH_BUFFER_BIT);
  960.     }
  961.  
  962.     accumBit = 1;        /* first available after counting bits */
  963.     
  964.     for(i = firstProduct; i <= lastProduct; i++)
  965.         if(drawProduct(i, accumBit++) == STOP)
  966.         goto doneWithFrame;
  967.  
  968.     COPY_AND_GOTO_IF_DONE("After drawing all target colors and depths");
  969.  
  970.     firstProduct = lastProduct + 1;
  971.     }
  972.  
  973.     if(showSurfaces) {
  974.     glDisable(GL_STENCIL_TEST);
  975.     glDepthMask(GL_FALSE);
  976.     glEnable(GL_CULL_FACE);
  977.     glCullFace(GL_BACK);
  978.     glEnable(GL_BLEND);
  979.     magicTranspHack = 1;
  980.     for(i = 0; i < numProducts[whichTree]; i++)
  981.     {
  982.         struct product *p;
  983.         p = &products[whichTree][i];
  984.  
  985.         if(i == curPrim || !showOnlyCurrent)
  986.         drawPrim(p->targetPrim);
  987.     }
  988.     magicTranspHack = 0;
  989.     glDisable(GL_BLEND);
  990.     }
  991.  
  992. doneWithFrame:
  993.  
  994.     glPopMatrix();
  995.  
  996.     copyInterest();
  997.     glutSwapBuffers();
  998. }
  999.  
  1000.  
  1001. enum trackballModeEnum {
  1002.     ROTATE,
  1003.     TRANSLATEXY,
  1004.     TRANSLATEZ,
  1005.     SCALEX,
  1006.     SCALEY,
  1007.     SCALEZ
  1008. } trackballMode = ROTATE;
  1009.  
  1010.  
  1011. /* ARGSUSED1 */
  1012. void special(int thing, int x, int y)
  1013. {
  1014.      switch(thing) {
  1015.          case GLUT_KEY_F1:
  1016.          prims[curPrim].draw = drawBox;
  1017.          glutPostRedisplay();
  1018.          break;
  1019.  
  1020.          case GLUT_KEY_F2:
  1021.          prims[curPrim].draw = drawCylinder;
  1022.          glutPostRedisplay();
  1023.          break;
  1024.  
  1025.          case GLUT_KEY_F3:
  1026.          prims[curPrim].draw = drawCone;
  1027.          glutPostRedisplay();
  1028.          break;
  1029.  
  1030.          case GLUT_KEY_F4:
  1031.          prims[curPrim].draw = drawSphere;
  1032.          glutPostRedisplay();
  1033.          break;
  1034.      }
  1035. }
  1036.  
  1037. /* ARGSUSED1 */
  1038. void keyboard(unsigned char key, int x, int y)
  1039. {
  1040.     switch(key)
  1041.     {
  1042.         case '1':
  1043.         case '2':
  1044.         case '3':
  1045.         case '4':
  1046.         whichTree = key - '1';
  1047.         glutPostRedisplay();
  1048.         break;
  1049.  
  1050.         case 'r':
  1051.         trackballMode = ROTATE;
  1052.         break;
  1053.  
  1054.     case 't':
  1055.         trackballMode = TRANSLATEXY;
  1056.         break;
  1057.  
  1058.     case 'T':
  1059.         trackballMode = TRANSLATEZ;
  1060.         break;
  1061.  
  1062.     case 'x':
  1063.         trackballMode = SCALEX;
  1064.         break;
  1065.  
  1066.     case 'y':
  1067.         trackballMode = SCALEY;
  1068.         break;
  1069.  
  1070.     case 'z':
  1071.         trackballMode = SCALEZ;
  1072.         break;
  1073.  
  1074.     case 'q': case 'Q': case '\033':
  1075.         exit(0);
  1076.         break;
  1077.  
  1078.     case '<': case ',':
  1079.         if(curXform != &globalXform)
  1080.         {
  1081.         curPrim = (curPrim - 1 + numPrims) % numPrims;
  1082.         curXform = &prims[curPrim].xform;
  1083.         printf("Manipulating transformation for object %d\n", curPrim);
  1084.         }
  1085.         else
  1086.         {
  1087.             printf("Have to toggle out of global mode first\n");
  1088.         }
  1089.         glutPostRedisplay();
  1090.         break;
  1091.  
  1092.     case '>': case '.':
  1093.         if(curXform != &globalXform)
  1094.         {
  1095.         curPrim = (curPrim + 1) % numPrims;
  1096.         curXform = &prims[curPrim].xform;
  1097.         printf("Manipulating transformation for object %d\n", curPrim);
  1098.         }
  1099.         else
  1100.         {
  1101.             printf("Have to toggle out of global mode first\n");
  1102.         }
  1103.         break;
  1104.  
  1105.     case 'g':
  1106.         if(curXform == &globalXform){
  1107.         curXform = &prims[curPrim].xform;
  1108.         printf("Manipulating transformation for object %d\n", curPrim);
  1109.         }else{
  1110.         curXform = &globalXform;
  1111.         printf("Manipulating global transformation\n");
  1112.         }
  1113.         break;
  1114.  
  1115.     case '+': case '=':
  1116.         whereToStop++;
  1117.         glutPostRedisplay();
  1118.         break;
  1119.  
  1120.     case '-': case '_':
  1121.         whereToStop--;
  1122.         glutPostRedisplay();
  1123.         break;
  1124.  
  1125.     case 's':
  1126.         glutPostRedisplay();
  1127.         showSurfaces = !showSurfaces;
  1128.         break;
  1129.  
  1130.     case 'c':
  1131.         doCSG = ! doCSG;
  1132.         if(doCSG)
  1133.         glutDisplayFunc(redrawCSG);
  1134.         else
  1135.         glutDisplayFunc(redrawNoCSG);
  1136.         glutPostRedisplay();
  1137.         break;
  1138.  
  1139.     case ' ':
  1140.         showOnlyCurrent = !showOnlyCurrent;
  1141.         glutPostRedisplay();
  1142.         break;
  1143.     }
  1144. }
  1145.  
  1146.  
  1147. static int ox, oy;
  1148.  
  1149. /* ARGSUSED */
  1150. void button(int b, int state, int x, int y)
  1151. {
  1152.     ox = x;
  1153.     oy = y;
  1154. }
  1155.  
  1156. void motion(int x, int y)
  1157. {
  1158.     int dx, dy;
  1159.  
  1160.     dx = x - ox;
  1161.     dy = y - oy;
  1162.  
  1163.     ox = x;
  1164.     oy = y;
  1165.  
  1166.     switch(trackballMode) {
  1167.     case ROTATE:
  1168.         rotateTrackball(dx, dy, curXform->rotation);
  1169.         break;
  1170.  
  1171.     case SCALEX:
  1172.         curXform->scale[0] += (dx + dy) / 40.0f;
  1173.         if(curXform->scale[0] < 1/40.0)
  1174.             curXform->scale[0] = 1/40.0;
  1175.         break;
  1176.  
  1177.     case SCALEY:
  1178.         curXform->scale[1] += (dx + dy) / 40.0f;
  1179.         if(curXform->scale[1] < 1/40.0)
  1180.             curXform->scale[1] = 1/40.0;
  1181.         break;
  1182.  
  1183.     case SCALEZ:
  1184.         curXform->scale[2] += (dx + dy) / 40.0f;
  1185.         if(curXform->scale[2] < 1/40.0)
  1186.             curXform->scale[2] = 1/40.0;
  1187.         break;
  1188.  
  1189.     case TRANSLATEXY:
  1190.         curXform->translation[0] += dx / 40.0f;
  1191.         curXform->translation[1] -= dy / 40.0f;
  1192.         break;
  1193.  
  1194.     case TRANSLATEZ:
  1195.         curXform->translation[2] += (dx + dy) / 40.0f;
  1196.         break;
  1197.     }
  1198.     glutPostRedisplay();
  1199. }
  1200.  
  1201.  
  1202. void reshape(int width, int height)
  1203. {
  1204.     glViewport(0, 0, width, height);
  1205.     winWidth = width;
  1206.     winHeight = height;
  1207.     resizeBuffers();
  1208.     glutPostRedisplay();
  1209. }
  1210.  
  1211.  
  1212. int mainMenu;
  1213.  
  1214.  
  1215. void mainMenuFunc(int choice)
  1216. {
  1217.     switch(choice)
  1218.     {
  1219.         case 1:
  1220.         doCSG = !doCSG;
  1221.         if(doCSG) {
  1222.             printf("CSG expression on\n");
  1223.         glutDisplayFunc(redrawCSG);
  1224.         glutChangeToMenuEntry(1, "Turn off CSG", 0);
  1225.         }
  1226.         else {
  1227.             printf("CSG expression off\n");
  1228.         glutDisplayFunc(redrawNoCSG);
  1229.         glutChangeToMenuEntry(1, "Turn on CSG", 0);
  1230.         }
  1231.         glutPostRedisplay();
  1232.         break;
  1233.         case 2:
  1234.         showSurfaces = !showSurfaces;
  1235.         if(showSurfaces) {
  1236.             printf("Transparent surfaces on\n");
  1237.         glutChangeToMenuEntry(2, "(s) Don't show objects transparent in CSG", 2);
  1238.         }
  1239.         else {
  1240.             printf("Transparent surfaces off\n");
  1241.         glutChangeToMenuEntry(2, "(s) Show objects transparent in CSG", 2);
  1242.         }
  1243.         glutPostRedisplay();
  1244.         break;
  1245.     }
  1246. }
  1247.  
  1248.  
  1249. void interestBufferFunc(int data)
  1250. {
  1251.     char *s;
  1252.  
  1253.     bufferInterest = data;
  1254.  
  1255.     switch(data) {
  1256.         case COLOR:
  1257.         s = "color";
  1258.         break;
  1259.  
  1260.         case STENCILVALUES:
  1261.         s = "stencil values";
  1262.         break;
  1263.  
  1264.         case STENCILPLANES:
  1265.         s = "individual stencil plane converage";
  1266.         break;
  1267.  
  1268.         case DEPTH:
  1269.         s = "depth";
  1270.         break;
  1271.     }
  1272.     printf("Now displaying %s data\n", s);
  1273.     glutPostRedisplay();
  1274. }
  1275.  
  1276.  
  1277. void csgMenuFunc(int data)
  1278. {
  1279.     whichTree = data;
  1280.     glutPostRedisplay();
  1281. }
  1282.  
  1283.  
  1284. void whichObjectFunc(int data)
  1285. {
  1286.     switch(data)
  1287.     {
  1288.         case 0:
  1289.         case 1:
  1290.         case 2:
  1291.         case 3:
  1292.         curPrim = data;
  1293.         curXform = &prims[curPrim].xform;
  1294.         printf("Editing object %d\n", data);
  1295.         break;
  1296.  
  1297.     case 4:
  1298.         curXform = &globalXform;
  1299.         printf("Editing global transformation %d\n", data);
  1300.         break;
  1301.     }
  1302. }
  1303.  
  1304.  
  1305. void morphMenuFunc(int data)
  1306. {
  1307.     switch(data) {
  1308.         case 0:
  1309.         prims[curPrim].draw = drawBox;
  1310.         glutPostRedisplay();
  1311.         break;
  1312.  
  1313.         case 1:
  1314.         prims[curPrim].draw = drawCylinder;
  1315.         glutPostRedisplay();
  1316.         break;
  1317.  
  1318.         case 2:
  1319.         prims[curPrim].draw = drawCone;
  1320.         glutPostRedisplay();
  1321.         break;
  1322.  
  1323.         case 3:
  1324.         prims[curPrim].draw = drawSphere;
  1325.         glutPostRedisplay();
  1326.         break;
  1327.      }
  1328. }
  1329.  
  1330.  
  1331. void helpFakeFunc(int d)
  1332. {
  1333. }
  1334.  
  1335.  
  1336. int main(int argc, char **argv)
  1337. {
  1338.     int bufferMenu;
  1339.     int csgMenu;
  1340.     int whichObjectMenu;
  1341.     int morphMenu;
  1342.     int helpFakeMenu;
  1343.  
  1344.     glutInitWindowSize(512,512);
  1345.     glutInit(&argc, argv);
  1346.     glutInitDisplayString("samples stencil>=3 rgb double depth");
  1347.     /* glutInitDisplayMode(GLUT_DOUBLE|GLUT_STENCIL|GLUT_DEPTH|GLUT_RGBA); */
  1348.     (void)glutCreateWindow("csg using stencil");
  1349.     glutDisplayFunc(redrawNoCSG);
  1350.     glutKeyboardFunc(keyboard);
  1351.     glutSpecialFunc(special);
  1352.     glutMotionFunc(motion);
  1353.     glutMouseFunc(button);
  1354.     glutReshapeFunc(reshape);
  1355.  
  1356.     glGetIntegerv(GL_STENCIL_BITS, &stenSize);
  1357.     printf("%d bits of stencil available in this visual\n", stenSize);
  1358.  
  1359.     printf("Hit 'S' to turn stencil on/off\n");
  1360.  
  1361.     bufferMenu = glutCreateMenu(interestBufferFunc);
  1362.     glutAddMenuEntry("Color data", COLOR);
  1363.     glutAddMenuEntry("Stencil values", STENCILVALUES);
  1364.     glutAddMenuEntry("Coverage in each stencil plane", STENCILPLANES);
  1365.     glutAddMenuEntry("Depth data", DEPTH);
  1366.  
  1367.     csgMenu = glutCreateMenu(csgMenuFunc);
  1368.     glutAddMenuEntry("(1) obj 1 MINUS obj 2", 0);
  1369.     glutAddMenuEntry("(2) obj 2 MINUS obj 1", 1);
  1370.     glutAddMenuEntry("(3) obj 1 AND obj 2", 2);
  1371.     glutAddMenuEntry("(4) (obj 1 AND obj 2) MINUS (obj 3 or obj 4)", 3);
  1372.  
  1373.     whichObjectMenu = glutCreateMenu(whichObjectFunc);
  1374.     glutAddMenuEntry("Object 1 (blue)", 0);
  1375.     glutAddMenuEntry("Object 2 (peach)", 1);
  1376.     glutAddMenuEntry("Object 3 (green)", 2);
  1377.     glutAddMenuEntry("Object 4 (purple)", 3);
  1378.     glutAddMenuEntry("(g) Toggle between global and local", 4);
  1379.  
  1380.     morphMenu = glutCreateMenu(morphMenuFunc);
  1381.     glutAddMenuEntry("(F1) Box", 0);
  1382.     glutAddMenuEntry("(F2) Cylinder", 1);
  1383.     glutAddMenuEntry("(F3) Cone", 2);
  1384.     glutAddMenuEntry("(F4) Sphere", 3);
  1385.  
  1386.     helpFakeMenu = glutCreateMenu(helpFakeFunc);
  1387.     glutAddMenuEntry("Click the left mouse button and drag to manipulate\n", 0);
  1388.     glutAddMenuEntry("Push 'r' to rotate like a trackball\n", 0);
  1389.     glutAddMenuEntry("Push 't' to translate in the X-Y plane\n", 0);
  1390.     glutAddMenuEntry("Push 'T' to translate in the Z axis\n", 0);
  1391.     glutAddMenuEntry("Push 'X' to scale in X\n", 0);
  1392.     glutAddMenuEntry("Push 'X' to scale in Y\n", 0);
  1393.     glutAddMenuEntry("Push 'Z' to scale in Z\n", 0);
  1394.  
  1395.     mainMenu = glutCreateMenu(mainMenuFunc);
  1396.     glutAddMenuEntry("(c) Turn on CSG", 1);
  1397.     glutAddMenuEntry("(s) Show objects transparent in CSG", 2);
  1398.     glutAddSubMenu("Buffer of interest", bufferMenu);
  1399.     glutAddSubMenu("Which CSG expression", csgMenu);
  1400.     glutAddSubMenu("Object for manipulation", whichObjectMenu);
  1401.     glutAddSubMenu("Turn current object into...", morphMenu);
  1402.     glutAddSubMenu("Help with moving and rotating:", helpFakeMenu);
  1403.     glutAttachMenu(GLUT_RIGHT_BUTTON);
  1404.     init();
  1405.     glutMainLoop();
  1406.  
  1407.     return 0;
  1408. }
  1409.